/*
 * $Id: IPTDSFTPCommand.java,v 1.6 2010/05/12 15:47:17 navdeep_mahajan Exp $
 * 
 * Copyright (C) 2008 General Electric Company. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of the General
 * Electric Company (GE). You shall not disclose this software and shall use it
 * only in accordance with the terms of the license agreement you entered into
 * with GE.
 * 
 * GE MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT. GE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING, OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES.
 */
package com.ge.healthcare.autosc.processor.iptds.transaction;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.ge.healthcare.autosc.common.ASCLogger;
import com.ge.healthcare.autosc.common.commands.IFTCommand;
import com.ge.healthcare.autosc.common.exceptions.BasicException;
import com.ge.healthcare.autosc.common.exceptions.FTPCommandException;
import com.ge.healthcare.autosc.common.exceptions.SFTPCommandException;
import com.ge.healthcare.autosc.processor.IPTDSCodeConstants;
import com.ge.healthcare.autosc.processor.exception.ClientDrvCommandException;
import com.ge.healthcare.autosc.processor.exception.IPTDSException;
import com.ge.healthcare.autosc.processor.iip.comm.ClientDrvCommand;
import com.ge.healthcare.autosc.processor.iip.comm.ClientDrvHeartBeat;
import com.ge.healthcare.autosc.processor.iip.comm.IIPResponseParser;
import com.ge.healthcare.autosc.processor.iip.comm.vo.FileInfo;
/**
 * 
 * @author 212042946
 *
 */
public class IPTDSFTPCommand {

	private IFTCommand ftpCommand = null;
	private List<String> retrievedFiles = new ArrayList<String>();
	
	/**
	 * Constructor
	 * @param ftpCommand
	 * @throws BasicException
	 */
	public IPTDSFTPCommand(IFTCommand ftpCommand) 
		throws BasicException {
		if(ftpCommand == null) {
			throw new BasicException("FTPCommand is not defined");
		}
		this.ftpCommand = ftpCommand;
	}

	/**
	 * Logout (disconnect) FTP connection
	 */
	public void logout()  {
		try {
			ftpCommand.logout();
		} catch (Exception e) {
			// There is nothing can do with it.
			ASCLogger.error(this.getClass(), "logout", "Exception while ftp logging out.", e);
		}
	}
	
	/**
	 * Check and get any CHF file from target system.
	 * @param lFile
	 * @param clientDrv
	 * @throws IPTDSException
	 */
	public boolean getMoreCHFFile(File lFile, ClientDrvCommand clientDrv) 
		throws IPTDSException {
		String methodName = "getMoreRemoteFile";
		ClientDrvHeartBeat heartBeat = null;
		boolean moreFile = false;
		if(lFile == null) {
			ASCLogger.error(this.getClass(), methodName,
				"local file name must be defined. Thread " + Thread.currentThread().getName());	
			throw new IPTDSException("local file is not defined. Thread" +
					Thread.currentThread().getName(), true);	
		}
		
		try {
			String threadName = "IPTDS-" + Thread.currentThread().getName();
			
			FileInfo remoteFileInfo = null;
			remoteFileInfo = getAnyFileInfoFromRemoteSystem(clientDrv);
			if((remoteFileInfo.getExitCode() != 0) && remoteFileInfo.isStdoutEmpty() == true) {
				ASCLogger.info("No available file need to get. Finished batch processing.");
			} else {
				heartBeat = new ClientDrvHeartBeat(clientDrv, threadName, true);
				if(heartBeat.isBeatable()) {
					heartBeat.start();
				} else {
					String msg = new StringBuffer()
						.append("Heart beat does not work, continue...\n")
						.append("{\n").append("Thread: ").append(threadName).append("}\n").toString();
					ASCLogger.warn(msg);
				}
				//If we have more files, get it!
				getFile(lFile, remoteFileInfo.getStdoutPath(), remoteFileInfo.getStdoutSize());
				moreFile = true;
			}
		} finally {
			if(heartBeat != null) {
				heartBeat.done();
			}
		}
		return moreFile;
	}
	
	/**
	 * Get remote file from the target system
	 * @param lFile
	 * @param rFile
	 * @param clientDrv
	 * @throws IPTDSException
	 */
	public void getRemoteFile(File lFile, File rFile,
			ClientDrvCommand clientDrv) throws IPTDSException {
		String methodName = "getRemoteFile";
		ClientDrvHeartBeat heartBeat = null;

		if(lFile == null || rFile == null) {
			ASCLogger.error(this.getClass(), methodName, 
					"local or remote file name must be defined. Thread " + 
					Thread.currentThread().getName());
			throw new IPTDSException("local or remote file is not defined. Thread " + 
					Thread.currentThread().getName(), true);
		}

		try {
			String threadName = "IPTDS-" + Thread.currentThread().getName();
			
			FileInfo remoteFileInfo = null;
			remoteFileInfo = getFileInfoFromRemoteSystem(rFile, clientDrv);
			heartBeat = new ClientDrvHeartBeat(clientDrv, threadName, true);
			if(heartBeat.isBeatable()) {
				heartBeat.start();
			} else {
				String msg = new StringBuffer()
					.append("Heart beat does not work, continue...\n")
					.append("{\n").append("Thread: ").append(threadName).append("}\n").toString();
				ASCLogger.warn(msg);
			}
			getFile(lFile, remoteFileInfo.getStdoutPath(), remoteFileInfo.getStdoutSize());
		} finally {
			if(heartBeat != null) {
				heartBeat.done();
			}
		}
	} 
	
	private void getFile(File lFile, String rFileName, int size) 
		throws IPTDSException {
		String methodName = "getFile";
		String errMsg = new StringBuffer()
			.append("Failed getting remote file ").append(rFileName)
			.append(" to local ").append(lFile.getPath()).toString();
		ASCLogger.info(this.getClass(), methodName, 
				"Get remote file " + rFileName + " to local directory of " + lFile.getPath());
		try {
			ftpCommand.setBinaryTransferMode();
			retrievedFiles.add(new File(rFileName).getName());
			ftpCommand.getFile(rFileName, lFile.getPath());
			ASCLogger.info(this.getClass(), methodName, 
					"Successfully get remote file " + rFileName + " to local directory of " + lFile.getPath());
		} catch (FTPCommandException ftpe) {
			ASCLogger.error(this.getClass(), methodName, errMsg, ftpe);
			throw new IPTDSException(errMsg, ftpe, IPTDSCodeConstants.PRC_F_TDS_009, true);
		} catch (SFTPCommandException sftpe) {
			ASCLogger.error(this.getClass(), methodName, errMsg, sftpe);
			throw new IPTDSException(errMsg, sftpe, IPTDSCodeConstants.PRC_F_TDS_009, true);
		}
	}
	
	private FileInfo getAnyFileInfoFromRemoteSystem(ClientDrvCommand clientDrv)
		throws IPTDSException {
		String methodName = "getAnyFileInfoFromRemoteSystem";
		String errMessage = new StringBuffer()
			.append("Cannot retrieve available remote file information. ").toString();
		FileInfo remoteFileInfo = null;
		try {
			String response = null;
				// no remote file specified, ask for more chf file.
			response = clientDrv.executeMkChfCommand();
			if(response == null) {
				ASCLogger.error(this.getClass(), methodName, 
						errMessage.toString());
				throw new IPTDSException(errMessage.toString(), IPTDSCodeConstants.PRC_F_TDS_008);
			}
			
			ASCLogger.info(this.getClass(), methodName, "Get reply: " + response);
			remoteFileInfo = IIPResponseParser.parseFileInformation(response);
			if(remoteFileInfo == null) {
				ASCLogger.error(this.getClass(), methodName, errMessage);
				throw new IPTDSException(errMessage, IPTDSCodeConstants.PRC_F_TDS_007);
			}
		} catch (ClientDrvCommandException cde) {
			ASCLogger.error(this.getClass(), methodName, errMessage.toString(), cde);
			throw new IPTDSException(errMessage.toString(), cde, 
					IPTDSCodeConstants.PRC_F_TDS_013, true);
		}
		return remoteFileInfo;
	}
	
	
	private FileInfo getFileInfoFromRemoteSystem(File rFile, ClientDrvCommand clientDrv)
		throws IPTDSException {
		String methodName = "getFileInfoFromRemoteSystem";
		String errMessage = new StringBuffer()
			.append("Cannot retrieve remote file information. ")
			.append("Remote file path: ").append(rFile.getPath()).toString();
		FileInfo remoteFileInfo = null;
		try {
			String response = null;
			response = clientDrv.executeGetInfoCommand(rFile.getPath());
			if(response == null) {
				ASCLogger.error(this.getClass(), methodName, 
						errMessage.toString());
				throw new IPTDSException(errMessage.toString(), IPTDSCodeConstants.PRC_F_TDS_008);
			}
	
			ASCLogger.info(this.getClass(), methodName, "Get reply: " + response);
			remoteFileInfo = IIPResponseParser.parseFileInformation(response);
			if((remoteFileInfo == null) || (remoteFileInfo.getExitCode() != 0)) {
				ASCLogger.error(this.getClass(), methodName, errMessage);
				throw new IPTDSException(errMessage, IPTDSCodeConstants.PRC_F_TDS_007);
			}
		} catch (ClientDrvCommandException cde) {
			ASCLogger.error(this.getClass(), methodName, errMessage.toString(), cde);
			throw new IPTDSException(errMessage.toString(), cde, 
					IPTDSCodeConstants.PRC_F_TDS_013, true);
		}
		return remoteFileInfo;
	}

	/**
	 * @return the retrievedFiles
	 */
	public List<String> getRetrievedFiles() {
		return retrievedFiles;
	}
}
